package person.rk.simfnc.interchange

import kotlin.experimental.and

import person.rk.simfnc.common.Util

class Response {
    companion object{
        enum class ErrKind{
            NoErr, Warn, ExecErr, ChkErr, UnkownErr
        }
        data class Status(val sw1: Byte, val sw2: Byte){
            val isValid: Boolean
                get() {
                    return sw1.and(0xf0.toByte()) == 0x90.toByte() ||
                            (sw1.and(0xf0.toByte()) == 0x60.toByte() && sw1.and(0x0f.toByte()) == 0.toByte())
                }
            val isErr: Boolean
                get() = sw1 in 0x64..0x6f
            val isNonVolatileMemoryChanged: Boolean
                get() = sw1 == 0x63.toByte() || sw1 == 0x65.toByte()
            val errKind: ErrKind
                get() = when(sw1){
                    0x90.toByte() -> if(sw2 == 0.toByte()) ErrKind.NoErr else ErrKind.UnkownErr
                    0x61.toByte() -> ErrKind.NoErr
                    in 0x62 .. 0x63 -> ErrKind.Warn
                    in 0x64 .. 0x66 -> ErrKind.ExecErr
                    in 0x67 .. 0x6f -> ErrKind.ChkErr
                    else -> ErrKind.UnkownErr
                }
            val meaning: String
                get() {
                    return when(sw1){
                        0x61.toByte() -> "Completed"
                        0x62.toByte() ->
                            when(sw2){
                                0.toByte() -> "No information given"
                                in 0x02 .. 0x80 -> "Triggering by the card (see 8.6.1)"
                                0x81.toByte() -> "Part of returned data may be corrupted"
                                0x82.toByte() -> "End of file or record reached before reading Ne bytes"
                                0x83.toByte() -> "Selected file deactivated"
                                0x84.toByte() -> "File control information not formatted according to 5.3.3"
                                0x85.toByte() -> "Selected file in termination state"
                                0x86.toByte() -> "No input data available from a sensor on the card"
                                else -> "???"
                            }
                        0x63.toByte() ->
                            when(sw2){
                                0x00.toByte() -> "No information given"
                                0x81.toByte() -> "File filled up by the last write"
                                in 0xc0 .. 0xcf -> "Counter from 0 to 15 encoded by 'X' (exact meaning depending on the command)"
                                else -> "???"
                            }
                        0x64.toByte() ->
                            when(sw2){
                                0x00.toByte() -> "Execution error"
                                0x01.toByte() -> "Immediate response required by the card"
                                in 0x20 .. 0x80 -> "Triggering by the card (see 8.6.1)"
                                else -> "???"
                            }
                        0x65.toByte() ->
                            when(sw2){
                                0x00.toByte() -> "No information given"
                                0x81.toByte() -> "Memory failure"
                                else -> "???"
                            }
                        0x68.toByte() ->
                            when(sw2){
                                0x00.toByte() -> "No information given"
                                0x81.toByte() -> "Logical channel not supported"
                                0x82.toByte() -> "Secure messaging not supported"
                                0x83.toByte() -> "Last command of the chain expected"
                                0x84.toByte() -> "Command chaining not supported"
                                else -> "???"
                            }
                        0x69.toByte() ->
                            when(sw2){
                                0x00.toByte() -> "No information given"
                                0x81.toByte() -> "Command incompatible with file structure"
                                0x82.toByte() -> "Security status not satisfied"
                                0x83.toByte() -> "Authentication method blocked"
                                0x84.toByte() -> "Reference data not usable"
                                0x85.toByte() -> "Conditions of use not satisfied"
                                0x86.toByte() -> "Command not allowed (no current EF)"
                                0x87.toByte() -> "Expected secure messaging data objects missing"
                                0x88.toByte() -> "Incorrect secure messaging data objects"
                                else -> "???"
                            }
                        0x6a.toByte() ->
                            when(sw2){
                                0x00.toByte() -> "No information given"
                                0x80.toByte() -> "Incorrect parameters in the command data field"
                                0x81.toByte() -> "Function not supported"
                                0x82.toByte() -> "File or application not found"
                                0x83.toByte() -> "Record not found"
                                0x84.toByte() -> "Not enough memory space in the file"
                                0x85.toByte() -> "Nc inconsistent with TLV structure"
                                0x86.toByte() -> "Incorrect parameters P1-P2"
                                0x87.toByte() -> "Nc inconsistent with parameters P1-P2"
                                0x88.toByte() -> "Referenced data or reference data not found (exact meaning depending on the command)"
                                0x89.toByte() -> "File already exists"
                                0x8a.toByte() -> "DF name already exists"
                                else -> "???"
                            }
                        else -> "Unknown"
                    }
                }
        }
    }

    private var _data: Util.ByteSlice? = null

    val data: Util.ByteSlice
        get() = _data!!.slice(0, -2)

    val status: Status
        get()  {
            val dx = _data!!.base
            val sw1 = dx[dx.size - 2]
            val sw2 = dx[dx.size - 1]
            return Status(sw1, sw2)
        }
}